#ifndef __ELF32_h
#define __ELF32_h
#include "stdtype.h"
#include "compiler.h"

#define ELF32_BIGENDIAN MX_CPU_BIGENDIAN

/// elf32 header

/* mx_elf32_ehdr_t.e_ident.mag* values */
#define ELF32_EHDR_E_IDENT_MAG0 0x7f            // e_ident[0]
#define ELF32_EHDR_E_IDENT_MAG1 'E'             // e_ident[1]
#define ELF32_EHDR_E_IDENT_MAG2 'L'             // e_ident[2]
#define ELF32_EHDR_E_IDENT_MAG3 'F'             // e_ident[3]
/* mx_elf32_ehdr_t.e_ident.class values */
#define ELF32_EHDR_E_IDENT_CLASSNONE 0          // e_ident[4] Invalid class
#define ELF32_EHDR_E_IDENT_CLASS32 1            // e_ident[4] 32-bit objects
#define ELF32_EHDR_E_IDENT_CLASS64 2            // e_ident[4] 64-bit objects
/* mx_elf32_ehdr_t.e_ident.data values */
#define ELF32_EHDR_E_IDENT_DATANONE 0           // Invalid data encoding
#define ELF32_EHDR_E_IDENT_DATA2LSB 1           // See below
#define ELF32_EHDR_E_IDENT_DATA2MSB 2           // See below

/* mx_elf32_ehdr_t.e_type values */
#define ELF32_EHDR_E_TYPE_NONE 0                // No file 
#define ELF32_EHDR_E_TYPE_REL 1                 // Relocatable 
#define ELF32_EHDR_E_TYPE_EXEC 2                // Executable 
#define ELF32_EHDR_E_TYPE_DYN 3                 // Shared object 
#define ELF32_EHDR_E_TYPE_CORE 4                // Core 
#define ELF32_EHDR_E_TYPE_LOPROC 0xff00         // Processorr-specific
#define ELF32_EHDR_E_TYPE_HIPROC 0xffff         // Processorr-specific

/* mx_elf32_ehdr_t.e_machine values */
#define ELF32_EHDR_E_MACHINE_NONE 0             // No machine
#define ELF32_EHDR_E_MACHINE_M32 1              // AT&T WE 32100
#define ELF32_EHDR_E_MACHINE_SPARC 2            // SPARC
#define ELF32_EHDR_E_MACHINE_386 3              // Intel Architecture
#define ELF32_EHDR_E_MACHINE_68K 4              // Motorola 68000
#define ELF32_EHDR_E_MACHINE_88K 5              // Motorola 88000
#define ELF32_EHDR_E_MACHINE_860 7              // Intel 80860
#define ELF32_EHDR_E_MACHINE_MIPS 8             // MIPS RS3000 Big-Endian
#define ELF32_EHDR_E_MACHINE_MIPS_RS4_BE 10     // MIPS RS4000 Big-Endian

/* mx_elf32_ehdr_t.e_version values */
#define ELF32_EHDR_E_VERSION_NONE 0             // Invalid versionn
#define ELF32_EHDR_E_VERSION_CURRENT 1          // Current version

/* elf32 header descriptor */
typedef struct {
    struct
    {
        mx_uint8_t mag0;                        // 0x7f
        mx_uint8_t mag1;                        // 'E'
        mx_uint8_t mag2;                        // 'L'
        mx_uint8_t mag3;                        // 'F'
        mx_uint8_t class;                       // file class
        mx_uint8_t data;                        // data encoding, MSB/LSB
        mx_uint8_t version;                     // file version, must be EV_CURRENT(1)
        mx_uint8_t pad;                         // start of padding bytes
        mx_uint8_t reserved[8];
    } e_ident;                                  // totle size = 16bytes
    mx_uint16_t e_type;
    mx_uint16_t e_machine;
    mx_uint32_t e_version;
    mx_uint32_t e_entry;                        // the entry point of program, for elf loader
    mx_uint32_t e_phoff;                        // the offset of program-header in file
    mx_uint32_t e_shoff;                        // the offset of section-header in file
    mx_uint32_t e_flags;
    mx_uint16_t e_ehsize;                       // the size of elf-header
    mx_uint16_t e_phentsize;                    // the size of a single entry in the program-header table, this is fixed value
    mx_uint16_t e_phnum;                        // the number of entrys in the program-header table
    mx_uint16_t e_shentsize;                    // the size of a single entry in the section-header table, this is fixed value
    mx_uint16_t e_shnum;                        // the number of entrys in the section-header talbe
    mx_uint16_t e_shstrndx;                     // an entry index of section-header table, this entry is a string table that holds the entry name of section-header table
 } mx_packed mx_elf32_ehdr_t, *mx_elf32_ehdr_pt;

/// section header

/* mx_elf32_shdr_t.sh_type values */
#define ELF32_SHDR_SH_TYPE_NULL 0
#define ELF32_SHDR_SH_TYPE_PROGBITS 1           // defined by program
#define ELF32_SHDR_SH_TYPE_SYMTAB 2             // section holds symbol table
#define ELF32_SHDR_SH_TYPE_STRTAB 3             // section holds string table
#define ELF32_SHDR_SH_TYPE_RELA 4               // section holds relocation entries, the single entry size see mx_elf32_shdr_t.sh_entsize
#define ELF32_SHDR_SH_TYPE_HASH 5               // section holds symbol hash table
#define ELF32_SHDR_SH_TYPE_DYNAMIC 6            // section holds information for dynamic linking
#define ELF32_SHDR_SH_TYPE_NOTE 7
#define ELF32_SHDR_SH_TYPE_NOBITS 8
#define ELF32_SHDR_SH_TYPE_REL 9
#define ELF32_SHDR_SH_TYPE_SHLIB 10
#define ELF32_SHDR_SH_TYPE_DYNSYM 11
#define ELF32_SHDR_SH_TYPE_LOPROC 0x70000000
#define ELF32_SHDR_SH_TYPE_HIPROC 0x7fffffff
#define ELF32_SHDR_SH_TYPE_LOUSER 0x80000000
#define ELF32_SHDR_SH_TYPE_HIUSER 0xffffffff

/* mx_elf32_shdr_t.sh_flags values */
#define ELF32_SHDR_SH_FLAGS_WRITE 0x1
#define ELF32_SHDR_SH_FLAGS_ALLOC 0x2
#define ELF32_SHDR_SH_FLAGS_EXECINSTR 0x4
#define ELF32_SHDR_SH_FLAGS_MASKPROC 0xf0000000

/* section header descriptor, entry */
typedef struct {
    mx_uint32_t sh_name;                        // the offset in mx_elf32_ehdr_t.e_shstrndx specified entry
    mx_uint32_t sh_type;
    mx_uint32_t sh_flags;
    mx_uint32_t sh_addr;                        // the section load address
    mx_uint32_t sh_offset;                      // the section offset in file
    mx_uint32_t sh_size;                        // the size of section
    mx_uint32_t sh_link;
    mx_uint32_t sh_info;
    mx_uint32_t sh_addralign;                   // section address alignment
    mx_uint32_t sh_entsize;                     // entry size if section's context consists of multiple items, like relocation entries
} mx_packed mx_elf32_shdr_t, *mx_elf32_shdr_pt;

/// symbol table

/* mx_elf32_sym_t.st_info.bind values */
#define ELF32_SYM_ST_INFO_BIND_LOCAL 0          // local symbol can be see in current file (static)
#define ELF32_SYM_ST_INFO_BIND_GLOBAL 1         // global symbol can be see in all project
#define ELF32_SYM_ST_INFO_BIND_WEAK 2           // weak symbol can be see in all project, but the global symbol of the same name overrides it
#define ELF32_SYM_ST_INFO_BIND_LOPROC 13        // reserved for processor-specific
#define ELF32_SYM_ST_INFO_BIND_HIPROC 15        // reserved for processor-specific

/* mx_elf32_sym_t.st_info.type values */
#define ELF32_SYM_ST_INFO_TYPE_NOTYPE 0
#define ELF32_SYM_ST_INFO_TYPE_OBJECT 1         // symbol is a variable
#define ELF32_SYM_ST_INFO_TYPE_FUNC 2           // symbol is a function
#define ELF32_SYM_ST_INFO_TYPE_SECTION 3        // symbol is associated with a section
#define ELF32_SYM_ST_INFO_TYPE_FILE 4
#define ELF32_SYM_ST_INFO_TYPE_LOPROC 13
#define ELF32_SYM_ST_INFO_TYPE_HIPROC 15

/* symbol table descriptor */
typedef struct {
    mx_uint32_t st_name;
    mx_uint32_t st_value;
    mx_uint32_t st_size;
    struct {
        mx_uint8_t type:4;                      // symbol type
        mx_uint8_t bind:4;                      // symbol bind
    } st_info;
    mx_uint8_t st_other;
    mx_uint16_t st_shndx;
} mx_packed mx_elf32_sym_t, *mx_elf32_sym_pt;

/// relocation table

/* mx_elf32_rel_t.r_info operations */
#define ELF32_REL_R_INFO_INDEX(r_info) ((r_info) >> 8)
#define ELF32_REL_R_INFO_TYPE(r_info) ((mx_uint8_t)(r_info))
#define ELF32_REL_R_INFO(index, type) (((index) << 8) | (mx_uint8_t)(type))

/* relocation table descriptor, for mx_elf32_shdr_t.sh_type == SH_TYPE_REL */
typedef struct {
    mx_uint32_t r_offset;
    struct
    {
#if (ELF32_BIGENDIAN)
        mx_uint16_t reserved;
        mx_uint8_t index;                       // specify a symbol's index that in symbol table
        mx_uint8_t type;                        // relocation type
#else
        mx_uint8_t type;
        mx_uint8_t index;
        mx_uint16_t reserved;
#endif
    } r_info;
} mx_packed mx_elf32_rel_t, *mx_elf32_rel_pt;

/* relocation table descriptor, for mx_elf32_shdr_t.sh_type == SH_TYPE_RELA */
typedef struct {
    mx_uint32_t r_offset;
    struct
    {
#if (ELF32_BIGENDIAN)
        mx_uint16_t reserved;
        mx_uint8_t index;                       // specify a symbol's index that in symbol table
        mx_uint8_t type;                        // relocation type
#else
        mx_uint8_t type;
        mx_uint8_t index;
        mx_uint16_t reserved;
#endif
    } r_info;
    mx_int32_t r_addend;
} mx_packed mx_elf32_rela_t, *mx_elf32_rela_pt;

/// dynamic table

/* mx_elf32_dyn_t.d_tag values */
                                                //   d_un
#define ELF32_DYN_D_TAG_NULL 0                  // (ignored) ignored Marks the end of the dynamic array
#define ELF32_DYN_D_TAG_NEEDED 1                // (d_val)   The string table offset of the name of a needed library（dynstr）
#define ELF32_DYN_D_TAG_PLTRELSZ 2              // (d_val)   Total size, in bytes, of the relocation entries associated with the procedure linkage table
#define ELF32_DYN_D_TAG_PLTGOT 3                // (d_ptr)   Contains an address associated with the linkage table The specific meaning of this field is processor-dependent
#define ELF32_DYN_D_TAG_HASH 4                  // (d_ptr)   Address of the symbol hash table, described below
#define ELF32_DYN_D_TAG_STRTAB 5                // (d_ptr)   Address of the dynamic string table
#define ELF32_DYN_D_TAG_SYMTAB 6                // (d_ptr)   Address of the dynamic symbol table
#define ELF32_DYN_D_TAG_RELA 7                  // (d_ptr)   Address of a relocation table with Elf64_Rela entries
#define ELF32_DYN_D_TAG_RELASZ 8                // (d_val)   Total size, in bytes, of the DT_RELA relocation table
#define ELF32_DYN_D_TAG_RELAENT 9               // (d_val)   Size, in bytes, of each DT_RELA relocation entry
#define ELF32_DYN_D_TAG_STRSZ 10                // (d_val)   Total size, in bytes, of the string table
#define ELF32_DYN_D_TAG_SYMENT 11               // (d_val)   Size, in bytes, of each symbol table entry
#define ELF32_DYN_D_TAG_INIT 12                 // (d_ptr)   Address of the initialization function
#define ELF32_DYN_D_TAG_FINI 13                 // (d_ptr)   Address of the termination function
#define ELF32_DYN_D_TAG_SONAME 14               // (d_val)   The string table offset of the name of this shared object
#define ELF32_DYN_D_TAG_RPATH 15                // (d_val)   The string table offset of a shared library search path string
#define ELF32_DYN_D_TAG_SYMBOLIC 16             // (ignored) ignored The presence of this dynamic table entry modifies the symbol resolution algorithm for references within the library Symbols defined within the library are used to resolve references before the dynamic linker searches the usual search path
#define ELF32_DYN_D_TAG_REL 17                  // (d_ptr)   Address of a relocation table with Elf64_Rel entries
#define ELF32_DYN_D_TAG_RELSZ 18                // (d_val)   Total size, in bytes, of the DT_REL relocation table
#define ELF32_DYN_D_TAG_RELENT 19               // (d_val)   Size, in bytes, of each DT_REL relocation entry
#define ELF32_DYN_D_TAG_PLTREL 20               // (d_val)   Type of relocation entry used for the procedure linkage table The d_val member contains either DT_REL or DT_RELA
#define ELF32_DYN_D_TAG_DEBUG 21                // (d_ptr)   Reserved for debugger use
#define ELF32_DYN_D_TAG_TEXTREL 22              // (ignored) ignored The presence of this dynamic table entry signals that the relocation table contains relocations for a non-writable segment
#define ELF32_DYN_D_TAG_JMPREL 23               // (d_ptr)   Address of the relocations associated with the procedure linkage table
#define ELF32_DYN_D_TAG_BIND_NOW 24             // (ignored) ignored The presence of this dynamic table entry signals that the dynamic loader should process all relocations for this object before transferring control to the program
#define ELF32_DYN_D_TAG_LOPROC 0x70000000       // (ignored) unspecified unspecified unspecified
#define ELF32_DYN_D_TAG_HIPROC 0x7fffffff       // (ignored) unspecified unspecified unspecified

/* dynamic table descripto, entry */
typedef struct {
    mx_int32_t d_tag;                           // controls the interpretation of `d_un`
    union {
        mx_uint32_t d_val;
        mx_uint32_t d_ptr;
    } d_un;
} mx_packed mx_elf32_dyn_t, *mx_elf32_dyn_pt;

/// program header

/* mx_elf32_phdr_t.p_type values */
#define ELF32_PHDR_P_TYPE_NULL 0                // unused entry
#define ELF32_PHDR_P_TYPE_LOAD 1                // loadable segment
#define ELF32_PHDR_P_TYPE_DYNAMIC 2             // dynamic linking tables
#define ELF32_PHDR_P_TYPE_INTERP 3              // program interpreter path name
#define ELF32_PHDR_P_TYPE_NOTE 4                // note sections
#define ELF32_PHDR_P_TYPE_SHLIB 5               // reserved
#define ELF32_PHDR_P_TYPE_PHDR 6                // program header table
#define ELF32_PHDR_P_TYPE_LOPROC 0x70000000     // processor use
#define ELF32_PHDR_P_TYPE_HIPROC 0x7fffffff     // processor use

/* program header descriptor, entry */
typedef struct {
    mx_uint32_t p_type;                         // Type of segment
    mx_uint32_t p_offset;                       // Offset in file
    mx_uint32_t p_vaddr;                        // Virtual address in memory
    mx_uint32_t p_paddr;                        // Reserved
    mx_uint32_t p_filesz;                       // Size of segment in file
    mx_uint32_t p_memsz;                        // Size of segment in memory
    mx_uint32_t p_flags;                        // Segment attributes
    mx_uint32_t p_align;                        // Alignment of segment
} mx_packed mx_elf32_phdr_t, *mx_elf32_phdr_pt;

#endif
